#include <stdlib.h>
#include <stdarg.h>

#include <errno.h>

#include <common/macro/build.h>
#include <common/macro/array.h>
#include <common/macro/debug.h>
#include <query/condition.h>
#include <query/filter.h>
#include <query/query.h>
#include <query/result.h>
#include <query/iterators/ftscan.h>
#include <storage/storage.h>
#include <storage/tuple/page_tuple.h>

API_LIBLOCAL result_e query_iterator_ftscan_step(query_t *query) {
	page_type_e page_type;
	page_size_t page_size;
	result_e result;

	if (query->iterator.page != NULL) {
		/* We already have a page open -- scan for next tuple.  */
		query->iterator.pointer.page_item++;

		if (query->iterator.pointer.page_item < query->iterator.page->tuple->tuples_c) {
			query->iterator.tuple = &query->iterator.page->tuple->tuples[query->iterator.pointer.page_item];
			return RESULT_OK;
		}

		/* We have exhausted this page, let's close it and request another one. */
		result = query->iterator.closepage(query, query->iterator.pointer.page_number, query->iterator.page);
		if (result != RESULT_OK) {
			query->iterator.page = NULL;
			query->iterator.tuple = NULL;
			return result;
		}

		query->iterator.pointer.page_number++;
		query->iterator.pointer.page_item = 0;

		query->iterator.page = NULL;
		query->iterator.tuple = NULL;
	}

	while (query->iterator.page == NULL) {
		if (storage_fsm_get_info(query->storage, query->iterator.pointer.page_number, &page_type, &page_size) != 0) {
			debugmsg("End of results.\n");
			return RESULT_ENDOFRESULTS;
		}
		
		/* FIXME: race condition. Page might have changed in the meantime, since we do not readlock FSM. */
		if (page_type != PAGE_TUPLE) {
			query->iterator.pointer.page_number++;
			continue;
		}

		result = query->iterator.openpage(query, query->iterator.pointer.page_number, &query->iterator.page);
		if (result != RESULT_OK) {
			query->iterator.page = NULL;
			query->iterator.tuple = NULL;
			return result;
		}
	}

	query->iterator.tuple = &query->iterator.page->tuple->tuples[query->iterator.pointer.page_item];
	return RESULT_OK;
}

API_LIBLOCAL result_e query_iterator_ftscan_finalize(query_t *query) {
	if (query->iterator.page == NULL)
		return RESULT_OK;

	return query->iterator.closepage(query, query->iterator.pointer.page_number, query->iterator.page);
}
